/*
 *  LunarLander.m
 *  pogostick
 *
 * In tribute to the game created by Jack Burness (where ever he is now)
 * that captivated me on that wonderful state of the art piece of hardware
 * (the Digital Equipment Corp. VT40 & PDP-11/34) when I was an undergraduate
 * at the University of Pittsburgh in the early 1970's.
 *
 *  Created by daddy (chuck@kollar.com) on 9/21/09.
 *  Copyright 2009 Charles P. Kollar All rights reserved.
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#import "LunarLander.h"


@implementation LEM

@synthesize shipBody;
@synthesize jointStaticBody;
@synthesize m;
@synthesize spaceWidth;
@synthesize spaceHeight;
@synthesize flightMax;

// These are defined in GameLayer.m. They need to be attached to a 'Layer'.
// This object isn't a layer, it's just a place to hold objects that exist
// in a level.
extern ParticleSystem *emitter;
extern ParticleSystem *thrustEmitter;

#define FLIGHTFORCE                 4000.0f


void shipBodyPositionFunc(struct cpBody *body, cpFloat dt)
{
    cpBodyUpdatePositionDefault(body, dt);
    // Not sure how to make a different function for an instance just yet.
    // probably need to map it into a structure and copy the address of an
    // instance method into the struct.
    LEM *me = (LEM *)body->data;
    cpFloat m = [me m];
    [thrustEmitter setPosition: ccp(body->p.x, body->p.y-18.0f*m)];
    cpVect flightMax = [me flightMax];
    // check to see if the LEM has flown out of the picture....
    if (body->p.x > flightMax.x || body->p.y > flightMax.y || body->p.x < 0.0f || body->p.y < 0.0f ) {
        // change the direction of flight by changing the force on the lem...
        cpBodyResetForces(body);
        cpVect angle = cpvforangle(body->a + M_PI/2); // 180 degrees out of phase (e.g, the opposite direction)
        cpVect impulse = cpvmult(angle, FLIGHTFORCE/4);
        cpBodyApplyForce(body, impulse, cpvzero);
    } 
}

-(id)initInSpace:(cpSpace *)space toStaticBody:(cpBody *)sb group:(int)group position:(cpVect)p size:(cpVect)size;
{
    return [self initInSpace:space toStaticBody:sb group:group position:p size:size flightMax:cpvzero];
}

-(id)initInSpace:(cpSpace *)space toStaticBody:(cpBody *)sb group:(int)group position:(cpVect)p size:(cpVect)size flightMax:(cpVect)fm;
{    
    if (self = [super init]) {
        flightMax = fm;
        m = size.x/28.0f; // magnification
        // hull must be convex, and winding clock wise...
        cpVect vertsTop[] = {
            cpv(-6.0f*m, 0.0f), cpv(-14.0f*m, 8.0f*m), cpv(-14.0f*m, 20.0f*m), cpv(-6.0f*m, 29.0f*m),
            cpv(6.0f*m, 29.0f*m), cpv(14.0f*m, 20.0f*m), cpv(14.0f*m, 8.0f*m), cpv(6.0f*m, 0.0f)
        };
        cpVect vertsBottom[] = {
            cpv(-17.0f*m, 0.0f), cpv(17.0f*m, 0.0f), cpv(17.0f*m, -16.0f*m), cpv(-17.0f*m, -16.0f*m)
        };
        cpFloat moment = 
        cpMomentForPoly(5.0f, (sizeof(vertsTop)/sizeof(cpVect)), vertsTop, cpvzero) +
        cpMomentForPoly(5.0f, (sizeof(vertsBottom)/sizeof(cpVect)), vertsBottom, cpvzero);
        shipBody = cpBodyNew(10.0f, moment);
        shipBody->p = p;
        shipBody->data = self;
        shipBody->position_func = &shipBodyPositionFunc;
        cpSpaceAddBody(space, shipBody);
        cpShape *shape;
        shape = cpPolyShapeNew(shipBody, (sizeof(vertsTop)/sizeof(cpVect)), vertsTop, cpvzero);
        shape->group = group;
        cpSpaceAddShape(space, shape);
        shape = cpPolyShapeNew(shipBody, (sizeof(vertsBottom)/sizeof(cpVect)), vertsBottom, cpvzero);
        shape->group = group;
        cpSpaceAddShape(space, shape);
        // landing legs...
        shape = cpSegmentShapeNew(shipBody, cpv(-17.0f*m, 0.0f), cpv(-32.0f*m, -24.0f*m), 0.0f);
		shape->group = group;
		cpSpaceAddStaticShape(space, shape);
        shape = cpSegmentShapeNew(shipBody, cpv(17.0f*m, 0.0f), cpv(32.0f*m, -24.0f*m), 0.0f);
		shape->group = group;
		cpSpaceAddStaticShape(space, shape);
        shape = cpSegmentShapeNew(shipBody, cpv(-17.0f*m, -14.0f*m), cpv(-28.0f*m, -18.0f*m), 0.0f);
		shape->group = group;
		cpSpaceAddStaticShape(space, shape);
        shape = cpSegmentShapeNew(shipBody, cpv(17.0f*m, -14.0f*m), cpv(28.0f*m, -18.0f*m), 0.0f);
		shape->group = group;
		cpSpaceAddStaticShape(space, shape);
        shape = cpSegmentShapeNew(shipBody, cpv(36.0f*m, -24.0f*m), cpv(28.0f*m, -24.0f*m), 0.0f);
		shape->group = group;
		cpSpaceAddStaticShape(space, shape);
        shape = cpSegmentShapeNew(shipBody, cpv(-28.0f*m, -24.0f*m), cpv(-36.0f*m, -24.0f*m), 0.0f);
		shape->group = group;
		cpSpaceAddStaticShape(space, shape);        
        shape = cpSegmentShapeNew(shipBody, cpv(-3.0f*m, -16.0f*m), cpv(-7.0f*m, -21.0f*m), 0.0f);
		shape->group = group;
		cpSpaceAddStaticShape(space, shape);        
        shape = cpSegmentShapeNew(shipBody, cpv(7.0f*m, -21.0f*m), cpv(3.0f*m, -16.0f*m), 0.0f);
		shape->group = group;
		cpSpaceAddStaticShape(space, shape);        
        
        jointStaticBody = cpGearJointNew(sb, shipBody, 0.0f, 1.0f);
		jointStaticBody->maxForce = 1e7; // something less than INFINITY that lets the stick wabble a bit...
		jointStaticBody->maxBias = 5.0f; // default is inf, but bias rarely goes over 10.0f
		cpSpaceAddConstraint(space, jointStaticBody);
        
        cpBodyApplyForce(shipBody, cpv(0.0f,FLIGHTFORCE), cpvzero);
    }
    return self;
}

-(void) performActions
{
    
}

-(void) thrust
{
    if (thrustEmitter != nil) {
        [thrustEmitter setTotalParticles: 500.0f];
        [thrustEmitter setAngle: 180.0f];
        [thrustEmitter setGravity: ccp(0.0f, 90.0f)];
    }
}

-(void) dealloc
{
    //cpBodyFree(shipBody);
    //cpConstraintFree(jointStaticBody);
    
	[super dealloc];
}

@end
